﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using SimpleExpression;

namespace SimpleExpression
{
    public class SqlServerSelectCommandStrategy : SqlSelectCommandStrategy
    {
        protected StringBuilder topClause;

        public SqlServerSelectCommandStrategy()
            :base(new SQLServerProvider())
        {
            this.topClause = new StringBuilder();
        }

        public override void AddAttribute(AttributeExpression expression)
        {
            base.AddAttribute(expression);
        }

        public override void AddPagingClause(PagingExpression expression)
        {
            if (expression.Limit > 0)
                this.topClause.AppendFormat("TOP {0}", expression.Limit);

            if (expression.Start > 0)
                this.pagingClause.AppendFormat("RowNumber > {0}", expression.Start);
        }

        protected override string GetCommandText()
        {
            bool complexQuery = this.pagingClause.Length > 0;

            StringBuilder builder = new StringBuilder();
            
            if(!complexQuery)
                AppendFlatQuery(builder, complexQuery);
            else
            {
                builder.Append("SELECT");

                if (this.topClause.Length > 0)
                {
                    builder.Append(SPACE);
                    builder.Append(this.topClause.ToString());
                }

                // Add aliases
                builder.Append(SPACE);
                builder.Append(string.Join(", ", this.attributesAliases.Select(c => string.Format("[{0}]", c)).ToArray()));
                
                builder.Append(Environment.NewLine);
                builder.Append("FROM");

                builder.Append(Environment.NewLine);
                builder.Append("(");

                builder.Append(Environment.NewLine);
                AppendFlatQuery(builder, complexQuery);

                builder.Append(Environment.NewLine);
                builder.Append(") T");
                
                if (this.pagingClause.Length > 0)
                {
                    builder.Append(Environment.NewLine);
                    builder.Append(SPACE);
                    builder.Append("WHERE");
                    builder.Append(SPACE);
                    builder.Append(this.pagingClause.ToString());
                }
            }

            return builder.ToString();
        }

        private string AppendFlatQuery(StringBuilder builder, bool complexQuery)
        {
            builder.Append("SELECT");

            if (!complexQuery && this.topClause.Length > 0)
            {
                builder.Append(SPACE);
                builder.Append(this.topClause.ToString());
            }

            builder.Append(SPACE);
            builder.Append(this.selectClause.ToString());

            if (complexQuery)
            {
                AddSeparator(builder);

                string format = "RowNumber = ROW_NUMBER() OVER (ORDER BY {0})";

                if (this.orderByClause.Length > 0)
                    builder.AppendFormat(format, this.orderByClause.ToString());
                else
                    builder.AppendFormat(format, this.selectClause.ToString());
            }

            builder.Append(Environment.NewLine);
            builder.Append("FROM");

            builder.Append(SPACE);
            builder.Append(this.fromClause.ToString());

            if (this.whereClause.Length > 0)
            {
                builder.Append(Environment.NewLine);
                builder.Append(SPACE);
                builder.Append("WHERE");
                builder.Append(SPACE);
                builder.Append(this.whereClause.ToString());
            }

            if (this.groupByClause.Length > 0)
            {
                builder.Append(Environment.NewLine);
                builder.Append("GROUP BY");
                builder.Append(SPACE);
                builder.Append(this.groupByClause.ToString());
            }
            
            if (!complexQuery && this.orderByClause.Length > 0)
            {
                builder.Append(Environment.NewLine);
                builder.Append("ORDER BY");
                builder.Append(SPACE);
                builder.Append(this.orderByClause.ToString());
            }

            return builder.ToString();
        }
    }
}
